package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.List;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONUtil;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.exception.ServiceException;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.DeviceShadowDataVo;
import com.zzyl.nursing.vo.ProductVo;
import io.jsonwebtoken.lang.Collections;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.domain.Device;
import com.zzyl.nursing.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import java.util.Arrays;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * deviceService业务层处理
 *
 * @author xiecong
 * @date 2025-05-30
 */
@Service
@Slf4j
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService {
    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private IoTDAClient client;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 查询device
     *
     * @param id device主键
     * @return device
     */
    @Override
    public Device selectDeviceById(Long id) {
        return getById(id);
    }

    /**
     * 查询device列表
     *
     * @param device device
     * @return device
     */
    @Override
    public List<Device> selectDeviceList(Device device) {
        return deviceMapper.selectDeviceList(device);
    }

    /**
     * 新增device
     *
     * @param device device
     * @return 结果
     */
    @Override
    public int insertDevice(Device device) {
        return save(device) ? 1 : 0;
    }

    /**
     * 修改device
     *
     * @param device device
     * @return 结果
     */
    @Override
    public int updateDevice(Device device) {
        return updateById(device) ? 1 : 0;
    }

    /**
     * 批量删除device
     *
     * @param ids 需要删除的device主键
     * @return 结果
     */
    @Override
    public int deleteDeviceByIds(Long[] ids) {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除device信息
     *
     * @param id device主键
     * @return 结果
     */
    @Override
    public int deleteDeviceById(Long id) {
        return removeById(id) ? 1 : 0;
    }

    /**
     * 同步产品列表
     */
    @Override
    public void syncProductList() {
        ListProductsRequest listProductsRequest = new ListProductsRequest();
        ListProductsResponse response = client.listProducts(listProductsRequest);
        List<ProductSummary> products = response.getProducts();
        // 只 保存产品名称和id
        List<ProductVo> productVoList = products.stream().map(p -> {
            ProductVo productVo = new ProductVo();
            productVo.setProductId(p.getProductId());
            productVo.setName(p.getName());
            return productVo;
        }).collect(Collectors.toList());
        redisTemplate.opsForValue().set(CacheConstants.ALL_PRODUCT_KEY, productVoList);
    }

    /**
     * 获取设备列表
     *
     * @return
     */
    @Override
    public List<ProductVo> allProduct() {
        List<ProductVo> projectVoList = (List<ProductVo>) redisTemplate.opsForValue().get(CacheConstants.ALL_PRODUCT_KEY);
        return projectVoList;
    }

    /**
     * 注册设备
     *
     * @param dto
     */
    @Override
    public void register(DeviceDto dto) {
        // 1、 设备名称不能重复
        Long count = lambdaQuery().eq(Device::getDeviceName, dto.getDeviceName()).count();
        if (count > 0) {
            throw new ServiceException("设备名称重复");
        }
        // 2、 设备标识码不能重复
        count = lambdaQuery().eq(Device::getNodeId, dto.getNodeId()).count();
        if (count > 0) {
            throw new ServiceException("设备标识码重复");
        }
        // 3、 同一位置不能安装同一产品设备
        count = lambdaQuery().eq(Device::getBindingLocation, dto.getBindingLocation())
                .eq(Device::getLocationType, dto.getLocationType())
                .eq(Device::getPhysicalLocationType, dto.getPhysicalLocationType())
                .count();
        if (count > 0) {
            throw new ServiceException("同一位置不能安装同一产品设备");
        }
        // 4、 请求华为云注册设备
        AddDeviceRequest request = new AddDeviceRequest();
        AddDevice body = new AddDevice();
        // 设置设备的属性
        body.setProductId(dto.getProductKey());
        body.setNodeId(dto.getNodeId());
        body.setDeviceName(dto.getDeviceName());
        //授权信息，密钥
        AuthInfo authInfo = new AuthInfo();
        String secret = UUID.fastUUID().toString(true);
        authInfo.setSecret(secret);
        body.setAuthInfo(authInfo);
        request.setBody(body);
        try {
            AddDeviceResponse response = client.addDevice(request);
            // 5、 保存到数据库
            Device device = BeanUtil.toBean(dto, Device.class);
            device.setIotId(response.getDeviceId());//iotId
            device.setSecret(secret);

            save(device);
        } catch (Exception e) {
            log.error("设备注册失败", e);
            throw new ServiceException("设备注册失败");
        }
    }

    /**
     * 获取设备详情
     *
     * @param iotId
     * @return
     */
    @Override
    public DeviceDetailVo getInfo(String iotId) {
        // 查询数据库
        Device device = lambdaQuery().eq(Device::getIotId, iotId).one();
        // 转化为vo
        DeviceDetailVo deviceDetailVo = BeanUtil.toBean(device, DeviceDetailVo.class);
        //  查询华为云
        ShowDeviceRequest showDeviceRequest = new ShowDeviceRequest();
        showDeviceRequest.setDeviceId(iotId);
        try {
            ShowDeviceResponse response = client.showDevice(showDeviceRequest);
            String status = response.getStatus();
            //  设置设备状态
            deviceDetailVo.setDeviceStatus(status);
            String activeTimeStr = response.getActiveTime();
            LocalDateTime activeTime = getLocalDateTime(activeTimeStr);
            deviceDetailVo.setActiveTime(activeTime);
        } catch (Exception e) {
            log.error("设备详情查询失败", e);
            throw new ServiceException("设备详情查询失败");
        }
        return deviceDetailVo;
    }

    /**
     * 查看设备上报的数据
     *
     * @param iotId
     * @return
     */
    @Override
    public List<DeviceShadowDataVo> queryServiceProperties(String iotId) {
        List<DeviceShadowDataVo> voList=null;
        // 查询华为云
        ShowDeviceShadowRequest request = new ShowDeviceShadowRequest();
        request.setDeviceId(iotId);
        try {
            ShowDeviceShadowResponse response = client.showDeviceShadow(request);
            List<DeviceShadowData> shadowList = response.getShadow();
            for (DeviceShadowData deviceShadowData : shadowList) {
                DeviceShadowProperties reported = deviceShadowData.getReported();
                String eventTimeStr = reported.getEventTime();
                LocalDateTime eventTime = getLocalDateTime2(eventTimeStr);
                Map<String, Object> properties = (Map<String, Object>) reported.getProperties();
                voList = properties.entrySet().stream().map(p -> {
                    DeviceShadowDataVo vo = new DeviceShadowDataVo();
                    vo.setFunctionId(p.getKey());
                    vo.setValue(p.getValue().toString());
                    vo.setEventTime(eventTime);
                    return vo;
                }).collect(Collectors.toList());
            }
        } catch (Exception e) {
            log.error("查看设备上报的数据失败", e);
            throw new ServiceException("查看设备上报的数据失败");
        }
        return voList;
    }

    private LocalDateTime getLocalDateTime(String timeStr) {
        if (StringUtils.hasText(timeStr)) {
            LocalDateTime activeTime = LocalDateTimeUtil.parse(timeStr, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
            //  UTC时间转换成本地时间
            activeTime = activeTime.atZone(ZoneId.from(ZoneOffset.UTC))
                    .withZoneSameInstant(ZoneId.systemDefault())
                    .toLocalDateTime();
            return activeTime;
        }
        return null;
    }

    private LocalDateTime getLocalDateTime2(String timeStr) {
        if (StringUtils.hasText(timeStr)) {
            LocalDateTime activeTime = LocalDateTimeUtil.parse(timeStr, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'"));
            //  UTC时间转换成本地时间
            activeTime = activeTime.atZone(ZoneId.from(ZoneOffset.UTC))
                    .withZoneSameInstant(ZoneId.systemDefault())
                    .toLocalDateTime();
            return activeTime;
        }
        return null;
    }
}
